﻿using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;

namespace TileMapEditor.Internal
{
    public static class ReflUnityInternal
    {
        private static Assembly _unity_editor_assembly;

        static ReflUnityInternal()
        {
            var prefix_path = Application.dataPath + @"/../";
            _unity_editor_assembly = Assembly.LoadFrom( prefix_path + @"Library/UnityAssemblies/UnityEngine.dll" );
        }

        public static Assembly UnityEditorAssembly
        {
            get { return _unity_editor_assembly; }
        }
    }

    /// <summary>
    /// Wrapper for SpriteEditorUtility
    /// </summary>
    public static class SpriteEdiotrUtilityWrapper
    {
        static Type tSpriteEditorUtility;

        static MethodInfo begin_lines_method = null;
        static MethodInfo end_lines_method = null;
        static MethodInfo draw_line_method = null;

        static SpriteEdiotrUtilityWrapper()
        {
            tSpriteEditorUtility = ReflUnityInternal.UnityEditorAssembly.GetType( "UnityEditorInternal.SpriteEditorUtility" );
            if ( null == tSpriteEditorUtility )
                return;

            begin_lines_method = tSpriteEditorUtility.GetMethod( "BeginLines", BindingFlags.Static | BindingFlags.Public );
            end_lines_method = tSpriteEditorUtility.GetMethod( "EndLines", BindingFlags.Static | BindingFlags.Public );
            draw_line_method = tSpriteEditorUtility.GetMethod( "DrawLine", BindingFlags.Static | BindingFlags.Public );
        }

        public static void BeginLines( Color color )
        {
            if ( begin_lines_method == null )
            {
                return;
            }

            begin_lines_method.Invoke( tSpriteEditorUtility, new object[] { color } );
        }

        public static void EndLines()
        {
            if ( null == end_lines_method )
            {
                return;
            }

            end_lines_method.Invoke( tSpriteEditorUtility, null );
        }

        public static void DrawLine( Vector3 v1, Vector3 v2 )
        {
            if ( null == draw_line_method )
            {
                return;
            }

            draw_line_method.Invoke( tSpriteEditorUtility, new object[] { v1, v2 } );
        }
    }

    /// <summary>
    /// Wrapper for HandlesUtility
    /// </summary>
    public static class HandlesUtilityWrapper
    {
        static Type tHandlesUtility = typeof( UnityEditor.HandleUtility );
        static MethodInfo apply_wire_material = null;

        public static void ApplyWireMaterial()
        {
            if ( null == apply_wire_material )
            {
                apply_wire_material = tHandlesUtility.GetMethod( "ApplyWireMaterial", BindingFlags.NonPublic | BindingFlags.Static );
            }

            apply_wire_material.Invoke( tHandlesUtility, null );
        }
    }

    /// <summary>
    /// Wrapper for TextureUtil
    /// </summary>
    public static class TextureUtilWrapper
    {
        static Type tTextureUtil;

        static MethodInfo set_filter_mode_no_dirty = null;

        static TextureUtilWrapper()
        {
            tTextureUtil = ReflUnityInternal.UnityEditorAssembly.GetType( "UnityEditor.TextureUtil" );
            if ( null == tTextureUtil )
                return;

            set_filter_mode_no_dirty = tTextureUtil.GetMethod( "SetFilterModeNoDirty", BindingFlags.Public | BindingFlags.Static );
        }

        public static void SetFilterModeNoDirty( Texture tex, FilterMode mode )
        {
            if ( null == set_filter_mode_no_dirty )
            {
                return;
            }

            set_filter_mode_no_dirty.Invoke( null, new object[] { tex, mode } );
        }
    }

    /// <summary>
    /// Wrapper for EditorGUIUtility
    /// </summary>
    public static class EditorGUIUtilityWrapper
    {
        static Type tEditorGUIUtility;
        static MethodInfo text_content = null;
        static PropertyInfo inspector_big = null;

        static EditorGUIUtilityWrapper()
        {
            tEditorGUIUtility = typeof( UnityEditor.EditorGUIUtility );
            if ( null == tEditorGUIUtility )
                return;

            text_content = tEditorGUIUtility.GetMethod( "TextContent", BindingFlags.NonPublic | BindingFlags.Static );
            inspector_big = tEditorGUIUtility.GetProperty( "inspectorBig", BindingFlags.NonPublic | BindingFlags.Static );
        }

        public static GUIStyle inspectorBig
        {
            get
            {
                if ( null == inspector_big )
                    return GUIStyle.none;

                var style = inspector_big.GetValue( null, null ) as GUIStyle;
                if ( null == style )
                    return GUIStyle.none;

                return style;
            }
        }

        public static GUIContent TextContent(string textAndTooltip)
        {
            if (null == text_content)
            {
                return GUIContent.none;
            }

            GUIContent result = text_content.Invoke( null, new object[] { textAndTooltip } ) as GUIContent;
            if ( null == result )
                return GUIContent.none;

            return result;
        }
    }

    /// <summary>
    /// Wrapper for GUIClip
    /// </summary>
    public static class GUIClipWrapper
    {
        static Type tGUIClip;
        static MethodInfo push = null;
        static MethodInfo pop = null;

        static GUIClipWrapper()
        {
            tGUIClip = ReflUnityInternal.UnityEditorAssembly.GetType( "UnityEngine.GUIClip" );
            if ( null == tGUIClip )
                return;

            push = tGUIClip.GetMethod( "Push", BindingFlags.NonPublic | BindingFlags.Static );
            pop = tGUIClip.GetMethod( "Pop", BindingFlags.NonPublic | BindingFlags.Static );
        }

        public static void Push( Rect screenRect, Vector2 scrollOffset, Vector2 renderOffset, bool resetOffset )
        {
            if ( null == push )
                return;

            push.Invoke( null, new object[] { screenRect, scrollOffset, renderOffset, resetOffset } );
        }

        public static void Pop()
        {
            if ( null == pop )
                return;

            pop.Invoke( null, null );
        }
    }
}

